package com.yifeng.repo.apm.endpoint.sender;

import com.yifeng.repo.apm.endpoint.utils.BaseUtil;
import next.fire.spinus.logx.utils.env.HostManager;

import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by daibing on 2020/12/26.
 */
public class LogSenderManager {
    private static final Integer STARTUP_RETRY_TIMES = 3;
    private static final Long REFRESH_INTERVAL_MILLIS = 3 * 60 * 1000L;
    private static final AtomicLong lastRefreshTime = new AtomicLong(0L);
    private static LogSender logSender;

    public static LogSender getLogSender(boolean refreshFilterParams) {
        if (logSender == null) {
            throw new RuntimeException("Please startup logSender first!");
        }
        if (!refreshFilterParams) {
            return logSender;
        }
        if (lastRefreshTime.get() + REFRESH_INTERVAL_MILLIS > System.currentTimeMillis()) {
            return logSender;
        }
        synchronized (lastRefreshTime) {
            if (lastRefreshTime.get() + REFRESH_INTERVAL_MILLIS > System.currentTimeMillis()) {
                return logSender;
            }
            buildRefreshThread().start();
            lastRefreshTime.set(System.currentTimeMillis());
        }
        return logSender;
    }

    public static void startupLogSender() {
        if (logSender == null) {
            logSender = buildLogSender();
        }
        for (int i = 0; i < STARTUP_RETRY_TIMES; i++) {
            if (logSender.isReady()) {
                break;
            }
            logSender.startup(i == STARTUP_RETRY_TIMES - 1);
            if (!logSender.isReady() && i < STARTUP_RETRY_TIMES - 1) {
                doWait(500);
            }
        }
        if (!logSender.isReady()) {
            throw new RuntimeException("startup log sender failed, check LogConfService first.");
        }
        lastRefreshTime.set(System.currentTimeMillis());
    }

    public static void shutdownSender() {
        if (logSender != null) {
            logSender.shutdown();
        }
    }

    private static LogSender buildLogSender() {
        HostManager util = HostManager.get();
        String appId = util.getEnvSetting("app.id", "app_id");
        String appStage = util.getEnvSetting("app.stage", "app_stage");
        String logConfUrl = util.getEnvSetting("log.conf.url");
        if (BaseUtil.isBlank(appId) || BaseUtil.isBlank(appStage) || BaseUtil.isBlank(logConfUrl)) {
            throw new RuntimeException(String.format("Not set boot args: appId=%s, appStage=%s, logConfUrl=%s", appId, appStage, logConfUrl));
        }
        return new LogSender(appId, appStage, logConfUrl);
    }

    private static Thread buildRefreshThread() {
        return new Thread("reload-log-filter-params") {
            @Override
            public void run() {
                logSender.refreshFilterParams();
            }
        };
    }

    private static void doWait(long time) {
        if (time <= 0) {
            return;
        }
        synchronized (LogSenderManager.class) {
            try {
                LogSenderManager.class.wait(time);
            } catch (InterruptedException e) {
                e.fillInStackTrace();
            }
        }
    }
}
